/*

ORBITER MODULE: BulletBaseVehicle

Project: surface-physics : http://code.google.com/p/surface-physics/

Description :This file implements the vehicle module for attaching to BulletBase's
and is meant to be controlled by the Bump physics plugin.

Written by Abhijit Nandy
License : Apache License 2.0

*/

#define STRICT
#define ORBITER_MODULE


#include "BulletBaseVehicle.h"

const float MAX_DIM = 5.0f;
double state = 0;

#define NO_KEY -1
char output[1000];

 

/**
 *  Unused constructor
 */
BulletBaseVehicle::BulletBaseVehicle (OBJHANDLE hVessel, int flightmodel)
: VESSEL3 (hVessel, flightmodel)
{
	//Do not set position, vessel object not yet constructed
	pos = _V(0., 0., 0.);
	yaw = 0.;
	pitch = 0.;
	roll = 0.;
	physicsPositionAvailable = false;

	//Engine parameters
	mass = 1500.f;
	maxEngineForce = 3000.f;//this should be engine/velocity dependent
	maxBrakingForce = 500.f;
	reverseEngineForce = -maxEngineForce/4;

	//Transmission : simple gear model which varies engine force only
	maxGear = 6; //Reverse and neutral indicated by 'R' & 'N'
	minGear = 1;
	
	//Steering parameters
	steeringIncrement = 0.04f;
	steeringClamp = 0.3f;

	//Wheel parameters
	wheelRadius = 1.5f;
	wheelWidth = 1.182f;	 //actual width is 2.364(twice)
	wheelFriction = 1500;
	wheelFwdBackDist = 5.4f;
	wheelLeftRightDist = 2.6f;
	connectionHeight = 1.2f;


	//Suspension parameters
	suspensionStiffness = 50.f;
	suspensionDamping = 20.0f;
	suspensionCompression = 2.4f;
	rollInfluence = 0.08f;
	suspensionRestLength = 0.9f;

	//Heights and initial location
	initialVehicleHeight = 2.0f; //Height from which vehicle is dropped on terrain at physics start
	chassisClearanceHeight = 1.2f; //Height of chassis above vehicle origin
	chassisLength = 6.0f;
	chassisWidth = 4.0f;
	chassisHeight = 2.0f;

}


/**
 *  Unused destructor
 */
BulletBaseVehicle::~BulletBaseVehicle ()
{
}


/**
 * Used to setup the basename etc, may need to be modified to support animation etc
 */
void BulletBaseVehicle::clbkSetClassCaps (FILEHANDLE cfg)
{
	//Physical specs
	SetSize (1.2);
	SetClipRadius(0.5);
	SetPMI (_V(0.61,0.01,0.62));
	SetEmptyMass(100);
	SetTouchdownPoints( _V(-0.1, 0, -0.07), _V(0.1, 0, -0.07), _V(0.0, 0, 0.170) );
	name = GetName();


	sprintf(output, "BulletBaseVehicle: clbkSetClassCaps called by %s", name);
	oapiWriteLog(output);

	VECTOR3 ofs = _V(0,0,0);

#ifdef BULLETBASE_WHEELANIM
	ofs = _V(0,0,0);
	AddMesh(name,&ofs);   //car mesh of same name as vessel name in scenario if debug mode
#else
	loadMeshFileDefaultNames(cfg);
	initAnimations();
#endif

	strcpy(baseName, "Brighton2");
	baseInited = false;
	shuttleAttached   = false;
	updateVessel = false;
	validKeyInput = false;
	meshesLoaded = false;

	hobjBBV = GetHandle();

	hobjShuttle = NULL;
	vShuttle = NULL;

	// --------- To get instruments working ----------------
	const double  PB_FUELMASS   = 750.0;           // max fuel mass [kg]
	const double  PB_ISP        = 5e4;             // fuel-specific impulse [m/s]
	const double  PB_MAXMAINTH  = 3e4;

	// propellant resources
	PROPELLANT_HANDLE hpr = CreatePropellantResource (PB_FUELMASS);

	// main engine
	THRUSTER_HANDLE th_main	= CreateThruster (_V(0,0,-4.35), _V(0,0,1), PB_MAXMAINTH, hpr, PB_ISP);
	CreateThrusterGroup (&th_main, 1, THGROUP_MAIN);




}

/**
 * MUST pass on the normal lines to orbiter, else no config file found critical error !!
 */
void BulletBaseVehicle::clbkLoadStateEx (FILEHANDLE scn,  void * status)
{
	char *line;	
	
	while (oapiReadScenario_nextline (scn, line)) {
		if (!_strnicmp (line, "PhysPosition", 12)) {  // custom item
			sscanf (line+12, "%lf %lf %lf %f %f %f", &pos.x, &pos.y, &pos.z, &yaw, &pitch, &roll);
			physicsPositionAvailable = true;  //must be falsed if vessel unloaded
		}
		else if (!_strnicmp (line, "Mass", 4)) {  // custom item
			sscanf (line+4, "%f", &mass);
		}
		else if (!_strnicmp (line, "MaxEngineForce", 14)) {  // custom item
			sscanf (line+14, "%f", &maxEngineForce);
		}
		else if (!_strnicmp (line, "MaxBrakingForce", 15)) {  // custom item
			sscanf (line+15, "%f", &maxBrakingForce);
		}
		else if (!_strnicmp (line, "ReverseEngineForce", 18)) {  // custom item
			sscanf (line+18, "%f", &reverseEngineForce);
		}
		else if (!_strnicmp (line, "MaxGear", 7)) {  // custom item
			sscanf (line+7, "%f", &maxGear);
		}
		else if (!_strnicmp (line, "MinGear", 7)) {  // custom item
			sscanf (line+7, "%f", &minGear);
		}
		else if (!_strnicmp (line, "SteeringIncrement", 17)) {  // custom item
			sscanf (line+17, "%f", &steeringIncrement);
		}
		else if (!_strnicmp (line, "SteeringClamp", 13)) {  // custom item
			sscanf (line+13, "%f", &steeringClamp);
		}
		else if (!_strnicmp (line, "WheelLeftForwardMeshFile", 24)) {  // custom item
			sscanf (line+24, "%s", mshWheelLeftForwardName);
		}
		else if (!_strnicmp (line, "WheelRightForwardMeshFile", 25)) {  // custom item
			sscanf (line+25, "%s", mshWheelRightForwardName);
		}
		else if (!_strnicmp (line, "WheelLeftRearMeshFile", 21)) {  // custom item
			sscanf (line+21, "%s", mshWheelLeftRearName);
		}
		else if (!_strnicmp (line, "WheelRightRearMeshFile", 22)) {  // custom item
			sscanf (line+22, "%s", mshWheelRightRearName);
		}
		else if (!_strnicmp (line, "WheelRadius", 10)) {  // custom item
			sscanf (line+11, "%f", &wheelRadius);
		}
		else if (!_strnicmp (line, "WheelWidth", 10)) {  // custom item
			sscanf (line+10, "%f", &wheelWidth);
		}
		else if (!_strnicmp (line, "WheelFriction", 13)) {  // custom item
			sscanf (line+13, "%f", &wheelFriction);
		}
		else if (!_strnicmp (line, "WheelForwardBackDistance", 24)) {  // custom item
			sscanf (line+24, "%f", &wheelFwdBackDist);
		}
		else if (!_strnicmp (line, "WheelLeftRightDistance", 22)) {  // custom item
			sscanf (line+22, "%f", &wheelLeftRightDist);
		}
		else if (!_strnicmp (line, "ChassisMeshFile", 15)) {  // custom item
			sscanf (line+15, "%s", mshChassisName);
		}
		else if (!_strnicmp (line, "ChassisClearanceHeight", 22)) {  // custom item
			sscanf (line+22, "%f", &chassisClearanceHeight);
		}
		else if (!_strnicmp (line, "ChassisWheelConnectionHeight", 28)) {  // custom item
			sscanf (line+28, "%f", &connectionHeight);
		}
		else if (!_strnicmp (line, "ChassisLength", 13)) {  // custom item
			sscanf (line+13, "%f", &chassisLength);
		}
		else if (!_strnicmp (line, "ChassisWidth", 12)) {  // custom item
			sscanf (line+12, "%f", &chassisWidth);
		}
		else if (!_strnicmp (line, "ChassisHeight", 13)) {  // custom item
			sscanf (line+13, "%f", &chassisHeight);
		}
		else if (!_strnicmp (line, "SuspensionStiffness", 19)) {  // custom item
			sscanf (line+19, "%f", &suspensionStiffness);
		}
		else if (!_strnicmp (line, "SuspensionDamping", 17)) {  // custom item
			sscanf (line+17, "%f", &suspensionDamping);
		}
		else if (!_strnicmp (line, "RollInfluence", 13)) {  // custom item
			sscanf (line+13, "%f", &rollInfluence);
		}
		else if (!_strnicmp (line, "SuspensionCompression", 21)) {  // custom item
			sscanf (line+21, "%f", &suspensionCompression);
		}
		else if (!_strnicmp (line, "SuspensionRestLength", 20)) {  // custom item
			sscanf (line+20, "%f", &suspensionRestLength);
		}
		else if (!_strnicmp (line, "InitialVehicleHeight", 20)) {  // custom item
			sscanf (line+20, "%f", &initialVehicleHeight);
		}
		else {          // anything not recognised is passed on to Orbiter
			ParseScenarioLineEx (line, status);
		}
	}

}


/**
 * Save state
 */
void BulletBaseVehicle::clbkSaveState( FILEHANDLE  scn )
{
	ClearAttachments();
	VESSEL3::clbkSaveState(scn);

	//Physics world position
	char buffer[100];
	sprintf(buffer, "%f %f %f %f %f %f", V3ARGS(pos), yaw, pitch, roll);
	oapiWriteScenario_string(scn, "PhysPosition", buffer);

	//Engine Parameters
	oapiWriteScenario_float(scn, "Mass", mass);
	oapiWriteScenario_float(scn, "MaxEngineForce", maxEngineForce);
	oapiWriteScenario_float(scn, "MaxBrakingForce", maxBrakingForce);
	oapiWriteScenario_float(scn, "ReverseEngineForce", reverseEngineForce);
	oapiWriteScenario_float(scn, "MaxGear", maxGear);
	oapiWriteScenario_float(scn, "MinGear", minGear);
	oapiWriteScenario_float(scn, "SteeringIncrement", steeringIncrement);
	oapiWriteScenario_float(scn, "SteeringClamp", steeringClamp);

	//Wheels
	oapiWriteScenario_string(scn, "WheelLeftForwardMeshFile", mshWheelLeftForwardName);
	oapiWriteScenario_string(scn, "WheelRightForwardMeshFile", mshWheelRightForwardName);
	oapiWriteScenario_string(scn, "WheelLeftRearMeshFile", mshWheelLeftRearName);
	oapiWriteScenario_string(scn, "WheelRightRearMeshFile", mshWheelRightRearName);
	oapiWriteScenario_float(scn, "WheelRadius", wheelRadius);
	oapiWriteScenario_float(scn, "WheelWidth", wheelWidth);
	oapiWriteScenario_float(scn, "WheelFriction", wheelFriction);
	oapiWriteScenario_float(scn, "WheelForwardBackDistance", wheelFwdBackDist);
	oapiWriteScenario_float(scn, "WheelLeftRightDistance", wheelLeftRightDist);

	//Chassis
	oapiWriteScenario_string(scn, "ChassisMeshFile", mshChassisName);
	oapiWriteScenario_float(scn, "ChassisClearanceHeight", chassisClearanceHeight);
	oapiWriteScenario_float(scn, "ChassisWheelConnectionHeight", connectionHeight);
	oapiWriteScenario_float(scn, "ChassisLength", chassisLength);
	oapiWriteScenario_float(scn, "ChassisWidth", chassisWidth);
	oapiWriteScenario_float(scn, "ChassisHeight", chassisHeight);

	//Suspension
	oapiWriteScenario_float(scn, "SuspensionStiffness", suspensionStiffness);
	oapiWriteScenario_float(scn, "SuspensionDamping", suspensionDamping);
	oapiWriteScenario_float(scn, "RollInfluence", rollInfluence);
	oapiWriteScenario_float(scn, "SuspensionRestLength", suspensionRestLength);

	//Position
	oapiWriteScenario_float(scn, "InitialVehicleHeight", initialVehicleHeight);


}
 
/**
 * Called every time step, find parent BulletBase at 1st call then run animations ?, print gear info ?
 */
void BulletBaseVehicle::clbkPreStep(double SimT, double SimDT, double MJD)
{
	//Find and store the base VESSEL : must be done here, before this all vessels have not loaded
	if(!baseInited)
		updateBase();

	if(updateVessel)
		runAnimations(NULL);

	if(!meshesLoaded){
		VECTOR3 ofs = _V(0,0,0);

		//Wheel Meshes
		AddMesh(mshWheelLeftForwardName, &ofs);
		AddMesh(mshWheelRightForwardName,&ofs);
		AddMesh(mshWheelLeftRearName,&ofs);
		AddMesh(mshWheelRightRearName,&ofs);

		ofs = _V(0.f, 1.2f, 0.f);
		AddMesh(mshChassisName, &ofs);

		meshesLoaded = true;
	}




	if((oapiGetFocusObject() == hobjBBV && updateVessel) || (shuttleAttached && oapiGetFocusObject() == hobjShuttle && updateVessel))
	{	
		switch(gear){
			case 'N': sprintf(oapiDebugString(),"Current gear :Neutral, Speed :%f km/hr", gear, speed); break;
			case 'R': sprintf(oapiDebugString(),"Current gear :Reverse, Speed :%f km/hr", gear, speed);	break;
			default:  sprintf(oapiDebugString(),"Current gear :%d, Speed :%.2f km/hr, bearing:%f", gear, speed);break;
		}
	}
		
}


/**
 * Capture and send keys to base when this VESSEL has focus.
 * Also attaches shuttle when '+' pressed & detaches when '-' pressed
 */
int BulletBaseVehicle::clbkConsumeBufferedKey(DWORD key, bool down, char *kstate) {

	//sprintf(oapiDebugString(),"down..%d", key);
	int context = 0;


	keyInput.key = key;
	keyInput.down = down;
	keyInput.kstate = kstate;

	validKeyInput = true;
	 

	if (down){	//key is pressed
		if (KEYMOD_SHIFT (kstate)) { //Shift key has also been pressed

		}
		else { // unmodified keys
			switch (key) {
				//Engine force
				case OAPI_KEY_G:
					attachShuttle();
					return 1;
				case OAPI_KEY_H:
					detachShuttle();
					return 1;
				default:
					;
					//vBase->clbkGeneric(2, key, &context);
			}





			//sprintf(oapiDebugString(),"baseCmd..%d", baseCmd);
		}
	}
	else{	//key was released
		if (KEYMOD_SHIFT (kstate)) {

		}
		else { // TODO convert context to vessel recognition struct later
			;//vBase->clbkGeneric(2, NO_KEY, &context);
		}
	}

	return 0;
}


/**
 * Receives commands to attach or detach shuttle from shuttle itself
 * msgid 1, prm 1 & 2 : used to receive attach and detach signals from ATV Shuttle
 * msgid 2, prm 1 : used to receive key commands from ATV Shuttle
 */
int	BulletBaseVehicle::clbkGeneric(int  msgid, int  prm , void *context)
{
	 
	switch(msgid){
		case 1:
			switch(prm){
				case 1:
					attachShuttle();
					break;
				case 2:
					detachShuttle();
					break;
				default:
					;
			}
			break;

		case 2:
			if(shuttleAttached){
				//Store ATVShuttle key press here
				KeyPressInfo *pkpi = (KeyPressInfo*)context;
				keyInput = (*pkpi);
				validKeyInput = true;
				//vBase->clbkGeneric(2, prm, context);
			}
			break;

		default:
			sprintf(oapiDebugString(),"ATV : Unknown message to clbkGeneric %d", msgid);
	}
	return 0;


}


/*
void BulletBaseVehicle::clbkFocusChanged(bool  getfocus, OBJHANDLE  hNewVessel, OBJHANDLE  hOldVessel)
{


	if(!getfocus){}
}
*/



/**
 * Attach the shuttle
 */
void BulletBaseVehicle::attachShuttle(void)
{
	char *strClassName;
	const char *athIDParent, *athIDChild;
	unsigned int numObj = oapiGetVesselCount();
	unsigned int i;
	VESSEL3 *v;
	OBJHANDLE hObj;

	if(shuttleAttached){
		sprintf(output, "Shuttle : %s is already attached !", vShuttle->GetName());
		oapiWriteLog(output);
		return;
	}


	/* Check and detach any other shuttle attachments ?
	 * No need as :
	 * bool VESSEL::AttachChild() API doc says :
	 *
	 * A child can only be connected to a single parent at any one time.
	 * If the child is already connected to a parent, the previous parent connection is severed.
	 *
	 * Thus if a connection with BulletBase exists it will be severed. After that BB wont attach
	 * shuttle to itself till shuttle has no other attachments.
	 *
	 * The other source of attachment may be any external object, that can't be halted without using
	 * parent attachment ID.
	 *
	 * Also shuttle needs to be removed from controlled vessels map, and set to landed state
	 * so its attached by BB after being detached by ATV, but skipped on the basis of being landed
	 * as long as its attached.
	 *
	 */



	//Scan the sim for ATVShuttles & attach the first one found
	for (i = 0; i < numObj; i++) {
		hObj = oapiGetVesselByIndex(i);
		v = (VESSEL3*)oapiGetVesselInterface(hObj);

		strClassName = v->GetClassName();
		if(strcmp(strClassName, "ATVShuttle") == 0){
			
			athParentShuttle = GetAttachmentHandle(false, 0);
			athChildShuttle = v->GetAttachmentHandle(true, 0);
			athIDChild  = GetAttachmentId(athParentShuttle);
			athIDParent = v->GetAttachmentId(athChildShuttle);

			if(athParentShuttle && athChildShuttle && AttachChild(hObj, athParentShuttle, athChildShuttle)
				){
				
				v->clbkGeneric(1, 1, GetHandle());
				shuttleAttached = true;
				hobjShuttle = hObj;
				vShuttle = v;

				//Set status to landed
				VESSELSTATUS2 vs;
				memset(&vs, 0, sizeof(VESSELSTATUS2));
				vs.version = 2;

				vShuttle->GetStatusEx(&vs);
				vs.status = 1;
				vShuttle->DefSetStateEx(&vs);

			}
			else{
				sprintf(output, "Attach failed: p:%d c:%d &p:%p, &c:%p", AttachmentCount(FALSE),
						vShuttle->AttachmentCount(TRUE), athParentShuttle, athChildShuttle);
				oapiWriteLog(output);
				sprintf(oapiDebugString(), output);
				shuttleAttached = false;
				hobjShuttle = NULL;
				vShuttle = NULL;
			}
		}
	}

}


/**
 * Detach the shuttle
 * TODO Separation velocity in upward direction not working, fixit
 */
void BulletBaseVehicle::detachShuttle()
{
	if(shuttleAttached && vShuttle){
		DetachChild(athParentShuttle, 20.0);
		vShuttle->clbkGeneric(1, 2, NULL);	//msgid 2 : send detached confirmation ATV -> ATVShuttle
		vShuttle = NULL;
		shuttleAttached = false;
		sprintf(oapiDebugString(),"ATV : Detach message received");
	}
	else
		sprintf(oapiDebugString(),"ATV : Shuttle is not shuttleAttached");
}


/**
 * Find the parent base which has attached this VESSEL to itself
 * TODO : use during handover when this vessel is passed over from 1 BulletBase
 * to another.
 */
void BulletBaseVehicle::updateBase(void)
{
	unsigned int i;
	char strObj[20];
	OBJHANDLE hBase;

	baseInited = false;

	unsigned int pac = AttachmentCount(true);

	for (i = 0; i < pac; i++) {

		athMineWithBase = GetAttachmentHandle(true, i);
		hBase = GetAttachmentStatus(athMineWithBase);

		if(hBase != NULL){
			vBase = (VESSEL3 *)oapiGetVesselInterface(hBase);
			oapiGetObjectName(hBase, strObj, 20);

			strcpy(baseName, strObj);
			sprintf(output, "BulletBaseVehicle : %s locking to controlling base %s", name, baseName);
						oapiWriteLog(output);

			baseInited = true;
			break;
		}

	}

}


//Load wheel and chassis mesh names from config file
//TODO Load from scenario file instead to allow instance based variation : important to tie bbv to proper bb
void BulletBaseVehicle::loadMeshFileDefaultNames(FILEHANDLE cfg)
{
	VECTOR3 ofs = _V(0,0,0);

	//Left Wheel
	if(oapiReadItem_string(cfg, "WheelLeftForwardMeshFile", mshWheelLeftForwardName))
		sprintf(output, "BulletBaseVehicle: loadMeshesFromFile : Read WheelLeft = %s", mshWheelLeftForwardName);
	else{
		sprintf(output, "BulletBaseVehicle: loadMeshesFromFile : Failed to read WheelLeft = %s", mshWheelLeftForwardName);
		sprintf(oapiDebugString(),output);
	}
	oapiWriteLog(output);

	if(oapiReadItem_string(cfg, "WheelLeftRearMeshFile", mshWheelLeftRearName))
		sprintf(output, "BulletBaseVehicle: loadMeshesFromFile : Read WheelLeft = %s", mshWheelLeftRearName);
	else{
		sprintf(output, "BulletBaseVehicle: loadMeshesFromFile : Failed to read WheelLeft = %s", mshWheelLeftRearName);
		sprintf(oapiDebugString(),output);
	}
	oapiWriteLog(output);


	//Right Wheel
	if(oapiReadItem_string(cfg, "WheelRightForwardMeshFile", mshWheelRightForwardName))
		sprintf(output, "BulletBaseVehicle: loadMeshesFromFile : Read WheelRight = %s", mshWheelRightForwardName);
	else{
		sprintf(output, "BulletBaseVehicle: loadMeshesFromFile : Failed to read WheelRight = %s", mshWheelRightForwardName);
		sprintf(oapiDebugString(),output);
	}
	oapiWriteLog(output);

	if(oapiReadItem_string(cfg, "WheelRightRearMeshFile", mshWheelRightRearName))
		sprintf(output, "BulletBaseVehicle: loadMeshesFromFile : Read WheelRight = %s", mshWheelRightRearName);
	else{
		sprintf(output, "BulletBaseVehicle: loadMeshesFromFile : Failed to read WheelRight = %s", mshWheelRightRearName);
		sprintf(oapiDebugString(),output);
	}
	oapiWriteLog(output);

	//Chassis
	if(oapiReadItem_string(cfg, "ChassisMeshFile", mshChassisName))
		sprintf(output, "BulletBaseVehicle: loadMeshesFromFile : Read ChassisMesh = %s", mshChassisName);
	else{
		sprintf(output, "BulletBaseVehicle: loadMeshesFromFile : Failed to read ChassisMesh = %s", mshChassisName);
		sprintf(oapiDebugString(),output);
	}
	oapiWriteLog(output);

}


//Initialize core animations for positioning wheels only
//TODO Convert wheel animation to mesh index based only
void BulletBaseVehicle::initAnimations()
{
	ANIMATIONCOMPONENT_HANDLE parent;
	static UINT group[] = {0}; // participating groups

	//Wheel Animations
	for(int i=0; i<4; i++){
		mgtTX[i] = new MGROUP_TRANSLATE( i, group, 0, _V(2*MAX_DIM, 0, 0));
		mgtTY[i] = new MGROUP_TRANSLATE	  ( i, group, 0, _V(0, 2*MAX_DIM, 0));
		mgtTZ[i] = new MGROUP_TRANSLATE	  ( i, group, 0, _V(0, 0, 2*MAX_DIM));
		mgrRY[i] = new MGROUP_ROTATE( i, group, 0, _V(0, 0, 0), _V(0, 1, 0), (float)(2 * PI) ); //steering
		mgrRX[i] = new MGROUP_ROTATE( i, group, 1, _V(0, 0, 0), _V(1, 0, 0), (float)(2 * PI) ); //rotation

		animTX[i] = CreateAnimation (0.5);
		parent = AddAnimationComponent (animTX[i], 0, 1, mgtTX[i]);

		animTY[i] = CreateAnimation (0.5);
		parent = AddAnimationComponent (animTY[i], 0, 1, mgtTY[i], parent);

		animTZ[i] = CreateAnimation (0.5);
		parent = AddAnimationComponent (animTZ[i], 0, 1, mgtTZ[i], parent);

		animRY[i] = CreateAnimation (0.0);
		parent = AddAnimationComponent (animRY[i], 0, 1, mgrRY[i], parent);

		animRX[i] = CreateAnimation (0.0);
		parent = AddAnimationComponent (animRX[i], 0, 1, mgrRX[i], parent);
	}

}

//Wheel animation. Mesh 0 & 1 are forward wheels and 2,3 are the rear wheels, 4 is chassis: THIS ORDER IS IMPORTANT!!
void BulletBaseVehicle::runAnimations(struct packet *pkt)
{
	double state = 0.0f;

	//Wheels
	for(int i=0; i<4; i++){

/*		switch(i){
		case 0:
			local.x = m1[12]; local.y = m1[13]; local.z = m1[14];
			break;

		case 1:
			local.x = m2[12]; local.y = m2[13]; local.z = m2[14];
			break;

		case 2:
			local.x = m3[12]; local.y = m3[13]; local.z = m3[14];
			break;

		case 3:
			local.x = m4[12]; local.y = m4[13]; local.z = m4[14];
			break;

		}

*/
		//Wheel connection point translation
		state = fabs(local[i].x/MAX_DIM);
		state *= 0.5; //reduce range to within  0 to 0.5 or 0.5 to 1
		state = (local[i].x > 0) ? 0.5+state : 0.5-state ; //-ve or +ve direction
		SetAnimation(animTX[i], state);

		state = fabs(local[i].y/MAX_DIM);
		state *= 0.5;
		state = (local[i].y > 0) ? 0.5+state : 0.5-state ;
		SetAnimation(animTY[i], state);

		state = fabs(local[i].z/MAX_DIM);
		state *= 0.5;
		state = (local[i].z > 0) ? 0.5+state : 0.5-state ;
		SetAnimation(animTZ[i], state);


		if(i<2){ //no steering for rear wheels
			state = ( steering<0 ? (2*PI - fabs(steering)) : steering)/(2*PI);
			SetAnimation(animRY[i], state);
		}

		//Wheel rotation
		double current_rot =  wheelRot[i] - ((int)(wheelRot[i]/(2*PI))*(2*PI)); //for absolute rotation
		
		state = ( current_rot<0 ? (2*PI - fabs(current_rot)) : current_rot)/(2*PI); //for -ve angles
		SetAnimation(animRX[i], state);

		/*if(i==0)
			sprintf(oapiDebugString(),"%f", current_rot);*/

	}


	

}


/**
 * Vessel initialisation
 */
DLLCLBK VESSEL *ovcInit (OBJHANDLE hvessel, int flightmodel)
{
	return new BulletBaseVehicle (hvessel, flightmodel);
}


/**
 * Vessel cleanup
 */
DLLCLBK void ovcExit (VESSEL *vessel)
{
	if (vessel) delete (BulletBaseVehicle*)vessel;
}


